package com.whz.crypt.advice;

import com.whz.crypt.config.CryptProperty;
import com.whz.crypt.config.CryptProperty.RsaProperty;
import com.whz.generic.crypt.aes.AesUtil;
import com.whz.generic.crypt.rsa.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

/**
 * @author whz
 */
@Slf4j
public class DecryptHttpInputMessage implements HttpInputMessage {

    private final HttpHeaders headers;
    private InputStream body;


    public DecryptHttpInputMessage(HttpInputMessage inputMessage, CryptProperty cryptProperty) {
        this.headers = inputMessage.getHeaders();
        try {
            this.body = inputMessage.getBody();
            if (this.body.available() == 0) {
                return;
            }

            String content = new BufferedReader(getStreamReader(inputMessage))
                    .lines()
                    .collect(Collectors.joining(System.lineSeparator()));

            String decryptBody = null;

            if (content.indexOf("{") > 0 || content.indexOf("}") > 0) {
                log.info("Unencrypted without decryption:{}", content);
                decryptBody = content;
            } else {
                if (!StringUtils.isEmpty(content)) {
                    switch (cryptProperty.getCryptType()) {
                    case AES: {
                        decryptBody = AesUtil.decrypt(content, cryptProperty.getAesProperty().getSecretKey());
                    }
                    break;
                    case RSA: {
                        StringBuilder json = rsaDecrypt(cryptProperty, content);
                        decryptBody = json.toString();
                    }
                    break;
                    default: {
                        log.warn("未知的加密类型.");
                        return;
                    }
                    }
                }
                if (cryptProperty.isPrintLog()) {
                    log.info("Encrypted data received：{},After decryption：{}", content, decryptBody);
                }
            }
            assert decryptBody != null;
            this.body = new ByteArrayInputStream(decryptBody.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("Http transport rsa decrypt error.", e);
            try {
                this.body = inputMessage.getBody();
            } catch (Exception ignored) {

            }
        }
    }

    private static StringBuilder rsaDecrypt(CryptProperty cryptProperty, String content) {
        StringBuilder json = new StringBuilder();
        String[] contents = content.replaceAll(" ", "+").split("\\|");
        for (String value : contents) {
            if (cryptProperty.getRsaProperty().getKeyType() == RsaProperty.KeyType.PRIVATE) {
                value = RsaUtils.decryptByPrivateKey(value, cryptProperty.getRsaProperty().getKey());
            } else {
                value = RsaUtils.decryptByPublicKey(value, cryptProperty.getRsaProperty().getKey());
            }
            json.append(value);
        }
        return json;
    }

    private static InputStreamReader getStreamReader(HttpInputMessage inputMessage) throws IOException {
        return new InputStreamReader(inputMessage.getBody());
    }

    @Override
    public InputStream getBody() {
        return body;
    }

    @Override
    public HttpHeaders getHeaders() {
        return headers;
    }
}